package com.chen.learnknowledge.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.chen.learnknowledge.config.MyElasticSearchConfig;
import com.chen.learnknowledge.constant.EsConstant;
import com.chen.learnknowledge.dao.UserDao;
import com.chen.learnknowledge.entity.User;
import com.chen.learnknowledge.service.UserService;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.GetIndexRequest;
import org.elasticsearch.common.unit.Fuzziness;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.RangeQueryBuilder;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.metrics.ParsedMax;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.naming.directory.SearchResult;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;

@Service
public class UserServiceImpl implements UserService {

    @Autowired
    UserDao userDao;

    @Resource
    RestHighLevelClient client;


    //调用方法批量保存user数据到es
    @Override
    public Boolean getUserAllAndInsertIntoEs() throws IOException {

        //先查出user里面所有的数据
       List<User> userList = userDao.getList();

        //创建批量新增请求对象
        BulkRequest request = new BulkRequest();
        for (User user:userList){
            //构造保存请求
            IndexRequest indexRequest = new IndexRequest(EsConstant.USER_INDEX);
            indexRequest.id(user.getId().toString());
            String userJSONString = JSON.toJSONString(user);
            indexRequest.source(userJSONString, XContentType.JSON);
            request.add(indexRequest);
        }
        BulkResponse bulk = client.bulk(request, MyElasticSearchConfig.COMMON_OPTIONS);
        Boolean isComplete =bulk.hasFailures();

        return isComplete;
    }

    //接收user数据并放入es当中
    @Override
    public void saveUserToEs(User user) throws IOException {
        //插入数据库
        userDao.addOne(user);
        //并且保存到es
        // 新增文档 - 请求对象
        IndexRequest request = new IndexRequest();
        // 设置索引及唯一性标识
        request.index(EsConstant.USER_INDEX).id(user.getId().toString());

        // 创建数据对象
        String toJSONString = JSON.toJSONString(user);
        // 添加文档数据，数据格式为 JSON 格式
        request.source(toJSONString, XContentType.JSON);
        // 客户端发送请求，获取响应对象
        IndexResponse response = client.index(request, MyElasticSearchConfig.COMMON_OPTIONS);
        System.out.println("_index:" + response.getIndex());
        System.out.println("_id:" + response.getId());
        System.out.println("_result:" + response.getResult());

    }

    //修改es中的数据
    @Override
    public void updateUserAndEs(User user) throws IOException {
        //TODO 修改mysql中的数据

        //修改es中的数据,指定索引和id
        IndexRequest request = new IndexRequest().index(EsConstant.USER_INDEX).id(user.getId().toString());
        request.source(JSON.toJSONString(user), XContentType.JSON);
        // 客户端发送请求，获取响应对象
        IndexResponse response = client.index(request, MyElasticSearchConfig.COMMON_OPTIONS);
        System.out.println("_index:" + response.getIndex());
        System.out.println("_id:" + response.getId());
        System.out.println("_result:" + response.getResult());
    }

    //从es中取数据
    @Override
    public User getEsById(Integer id) throws IOException {
        //1.创建请求对象
        GetRequest getRequest = new GetRequest().index(EsConstant.USER_INDEX).id(id.toString());
        //2.客户端发送请求，获取响应对象
        GetResponse getResponse = client.get(getRequest, MyElasticSearchConfig.COMMON_OPTIONS);
        System.out.println("_index:" + getResponse.getIndex());
        System.out.println("_type:" + getResponse.getType());
        System.out.println("_id:" + getResponse.getId());
        System.out.println("source:" + getResponse.getSourceAsString());
        String userString = getResponse.getSourceAsString();
        User user = JSONObject.parseObject(userString, User.class);
        System.out.println(user);
        return user;
    }

    //根据id删除数据
    @Override
    public void deleteEsById(Integer id) throws IOException {

        //1.创建请求对象
        DeleteRequest deleteRequest = new DeleteRequest().index(EsConstant.USER_INDEX).id(id.toString());
        //2.客户端发送请求，获取响应对象
        DeleteResponse response = client.delete(deleteRequest, MyElasticSearchConfig.COMMON_OPTIONS);
        System.out.println(response.getResult());
        System.out.println(response.toString());
    }

    //批量删除
    @Override
    public void bulkDeleteEs(List<Integer> ids) throws IOException {
        BulkRequest bulkRequest = new BulkRequest();
        for (Integer id:ids){
            bulkRequest.add(new DeleteRequest().index(EsConstant.USER_INDEX).index(id.toString()));
        }
        //客户端发送请求
        BulkResponse responses = client.bulk(bulkRequest, MyElasticSearchConfig.COMMON_OPTIONS);
        //打印结果信息
        System.out.println("took:" + responses.getTook());
        System.out.println("items:" + responses.getItems());
    }

    //查询所有索引数据
    @Override
    public List<User> getAllFromEs() throws IOException {
        List<User> userList=new LinkedList<User>();

        //构建检索请求
        SearchRequest searchRequest = new SearchRequest().indices("user");
        //构建请求体查询所有数据
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder().query(QueryBuilders.matchAllQuery());
        searchRequest.source(sourceBuilder);
        SearchResponse searchResponse = client.search(searchRequest,MyElasticSearchConfig.COMMON_OPTIONS);
        SearchHits searchResponseHits = searchResponse.getHits();
        for(SearchHit hit:searchResponseHits) {
            System.out.println(hit.getSourceAsString());
            userList.add(JSONObject.parseObject(hit.getSourceAsString(),User.class));
        }
        System.out.println(userList);
        return userList;
    }

    /**
     * 条件查询
     * @return
     */
    @Override
    public List<User> getUserFromEsByUserElement() throws IOException {
        List<User> userList = new LinkedList<User>();

        //构建检索请求
        SearchRequest searchRequest = new SearchRequest().indices(EsConstant.USER_INDEX);
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.query(QueryBuilders.matchQuery("age","18"));
        searchRequest.source(searchSourceBuilder);
        SearchResponse searchResponse = client.search(searchRequest, MyElasticSearchConfig.COMMON_OPTIONS);
        SearchHits hits = searchResponse.getHits();
        for (SearchHit hit:hits){
            String sourceAsString = hit.getSourceAsString();
            User user = JSONObject.parseObject(sourceAsString, User.class);
            userList.add(user);
        }

        //输出一下结果
        System.out.println(userList);
        return userList;
    }


    //分页查询
    @Override
    public List<User> getUserFromEsWithPage(Integer pageNum,Integer pageSize) throws IOException {

        List<User> userList = new LinkedList<User>();

        //构建检索请求
        SearchRequest searchRequest = new SearchRequest().indices(EsConstant.USER_INDEX);

        // 构建查询的请求体
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.query(QueryBuilders.matchAllQuery());

        // 分页查询
        // 当前页其实索引(第一条数据的顺序号)， from
        searchSourceBuilder.from(pageNum);

        // 每页显示多少条 size
        searchSourceBuilder.size(pageSize);

        //提交查询
        searchRequest.source(searchSourceBuilder);
        SearchResponse searchResponse = client.search(searchRequest, MyElasticSearchConfig.COMMON_OPTIONS);
        SearchHits hits = searchResponse.getHits();
        for (SearchHit hit : hits){
            String sourceAsString = hit.getSourceAsString();
            userList.add(JSONObject.parseObject(sourceAsString,User.class));
        }
        System.out.println(userList);

        return userList;
    }

    //排序查询
    @Override
    public List<User> getUserFromEsOrderByAge() throws IOException {
        List<User> userList = new LinkedList<User>();

        //构建检索请求
        SearchRequest searchRequest = new SearchRequest().indices(EsConstant.USER_INDEX);

        // 构建查询的请求体
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.query(QueryBuilders.matchAllQuery());
        searchSourceBuilder.sort("age", SortOrder.ASC);

        //提交查询
        searchRequest.source(searchSourceBuilder);
        SearchResponse searchResponse = client.search(searchRequest, MyElasticSearchConfig.COMMON_OPTIONS);
        SearchHits hits = searchResponse.getHits();
        for (SearchHit hit : hits){
            String sourceAsString = hit.getSourceAsString();
            userList.add(JSONObject.parseObject(sourceAsString,User.class));
        }
        System.out.println(userList);

        return userList;
    }

    //多条件组合排序查询
    @Override
    public List<User> getUserFromEsByElements() throws IOException {
        List<User> userList = new LinkedList<>();

        //构建检索请求
        SearchRequest searchRequest = new SearchRequest().indices(EsConstant.USER_INDEX);

        // 构建查询的请求体
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        // 必须包含
        boolQueryBuilder.must(QueryBuilders.matchQuery("age",18));
        //一定不含有（名字带了芳的都查不出来。es默认单个中文分词）
        boolQueryBuilder.mustNot(QueryBuilders.matchQuery("userName","芳"));
        //可以包含
        boolQueryBuilder.should(QueryBuilders.matchQuery("sex","男"));
        searchSourceBuilder.query(boolQueryBuilder);

        //排序
        searchSourceBuilder.sort("age", SortOrder.ASC);

        //提交查询
        searchRequest.source(searchSourceBuilder);
        SearchResponse searchResponse = client.search(searchRequest, MyElasticSearchConfig.COMMON_OPTIONS);
        SearchHits hits = searchResponse.getHits();
        for (SearchHit hit : hits){
            String sourceAsString = hit.getSourceAsString();
            userList.add(JSONObject.parseObject(sourceAsString,User.class));
        }
        System.out.println(userList);

        return userList;
    }

    //范围查询
    @Override
    public List<User> getUserFromEsByRange() throws IOException {

        List<User> userList = new LinkedList<>();

        //构建检索请求
        SearchRequest searchRequest = new SearchRequest().indices(EsConstant.USER_INDEX);

        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        boolQueryBuilder.must(QueryBuilders.matchQuery("userName","余震"));
        RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery("age");

        //大于等于
        //rangeQueryBuilder.gte(18)

        //小于等于
        rangeQueryBuilder.lte(35);

        //提交查询
        searchSourceBuilder.query(rangeQueryBuilder);
        searchSourceBuilder.query(boolQueryBuilder);
        searchSourceBuilder.sort("age",SortOrder.ASC);
        searchRequest.source(searchSourceBuilder);
        SearchResponse searchResponse = client.search(searchRequest, MyElasticSearchConfig.COMMON_OPTIONS);
        SearchHits hits = searchResponse.getHits();
        for (SearchHit hit : hits){
            String sourceAsString = hit.getSourceAsString();
            userList.add(JSONObject.parseObject(sourceAsString,User.class));
        }
        System.out.println(userList);

        return userList;
    }

    //模糊查询
    @Override
    public List<User> getUserFromEsByFuzzyQuery() throws IOException {

        List<User> userList = new LinkedList<>();

        //构建检索请求
        SearchRequest searchRequest = new SearchRequest().indices(EsConstant.USER_INDEX);

        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        //value最好由前端传值过来
        searchSourceBuilder.query(QueryBuilders.fuzzyQuery("userName","余震").fuzziness(Fuzziness.ONE));

        searchRequest.source(searchSourceBuilder);
        SearchResponse searchResponse = client.search(searchRequest, MyElasticSearchConfig.COMMON_OPTIONS);
        SearchHits hits = searchResponse.getHits();
        for (SearchHit hit : hits){
            String sourceAsString = hit.getSourceAsString();
            userList.add(JSONObject.parseObject(sourceAsString,User.class));
        }
        System.out.println(userList);

        return userList;
    }

    //求age最大的user
    @Override
    public String getUserFromEsByMaxValue() throws IOException {
        List<User> userList = new LinkedList<>();

        //构建检索请求
        SearchRequest searchRequest = new SearchRequest().indices(EsConstant.USER_INDEX);

        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.aggregation(AggregationBuilders.max("maxAge").field("age"));

        searchRequest.source(searchSourceBuilder);
        SearchResponse searchResponse = client.search(searchRequest, MyElasticSearchConfig.COMMON_OPTIONS);
        //4.打印响应结果
        //TODO 怎么拿出下面的数据
        ParsedMax aggregation = searchResponse.getAggregations().get("maxAge");

        //"aggregations":{"max#maxAge":{"value":40.0}}}
        System.out.println(aggregation.getValue());

        return null;
    }

    /**
     * 分组查询
     */
    public String getUserFromEsByTerm() throws IOException{
        SearchRequest request = new SearchRequest().indices("user");
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        sourceBuilder.aggregation(AggregationBuilders.terms("age_groupby").field("age"));
        //设置请求体
        request.source(sourceBuilder);
        //3.客户端发送请求，获取响应对象
        SearchResponse response = client.search(request, MyElasticSearchConfig.COMMON_OPTIONS);
        //4.打印响应结果
        Terms classroomTerm = response.getAggregations().get("age_groupby");;
        for(Terms.Bucket classroomBucket:classroomTerm.getBuckets()){
                System.out.println("classRoom:"+classroomBucket.getKeyAsString());
        }

        return null;

    }
}
